package com.roamer.javase.demo.algorithm;

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author roamer
 * @version v1.0
 * @date 2020/3/24 17:45
 */
public class Juc {


    public static void cyclicBarrierTest() throws InterruptedException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> System.out.println("执行完毕"));
        ExecutorService executorService = new ThreadPoolExecutor(3, 3, 10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(1),
                new CustomizeThreadFactory("cyclic"));
        for (int i = 0; i < 3; i++) {
            int finalI = i;
            executorService.execute(() -> {
                try {
                    Thread.sleep(finalI * 1000);
                    System.out.printf("[%s]执行完毕，前面有[%s]个已到达 \n", Thread.currentThread().getName(),
                            cyclicBarrier.getNumberWaiting());
                    cyclicBarrier.await();
                    System.out.printf("[%s]都到咯 \n", Thread.currentThread().getName());
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }

            });
        }

        Thread.sleep(3000);
        executorService.shutdown();

    }

    public static void downLatchTest() throws InterruptedException {
        CountDownLatch downLatch = new CountDownLatch(3);
        ExecutorService executorService = new ThreadPoolExecutor(1, 2, 10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(1),
                new CustomizeThreadFactory("down"));
        for (int i = 0; i < 3; i++) {
            executorService.execute(() -> {
                downLatch.countDown();
                System.out.printf("[%s]执行完毕，剩余：%s \n", Thread.currentThread().getName(), downLatch.getCount());
            });
        }
        downLatch.await();
        executorService.shutdown();
        System.out.println("执行完毕");
    }

    static class CustomizeThreadFactory implements ThreadFactory {
        private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
        private final AtomicInteger threadNumber = new AtomicInteger(0);
        private final ThreadGroup group;
        private final String name;

        public CustomizeThreadFactory(String namePrefix) {
            if (namePrefix == null || "".equals(namePrefix)) {
                throw new IllegalArgumentException("namePrefix Cannot be null or empty!");
            }
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            this.name = namePrefix + "-" + POOL_NUMBER.getAndIncrement() + "-thread-";
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r, name + threadNumber.getAndIncrement(), 0);
            if (t.isDaemon()) {
                t.setDaemon(false);
            }
            if (t.getPriority() != Thread.NORM_PRIORITY) {
                t.setPriority(Thread.NORM_PRIORITY);
            }
            return t;
        }
    }

    public static void phaserTest() {
        System.out.println("准备开始抽奖了，等待各位选手就绪");
        Phaser phaser = new Phaser(5) {
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                switch (phase) {
                    case 0:
                        System.out.println("全部选手就绪完毕，当前人数：" + registeredParties);
                        System.out.println("准备开始第一关\n");
                        return false;
                    case 1:
                        System.out.println("第一关结束，剩余人数：" + registeredParties);
                        System.out.println("准备开始最终关卡\n");
                        return false;
                    case 2:
                        System.out.println("最终关卡通关人数：" + registeredParties);
                        System.out.println("闯关结束\n");
                        return true;
                    default:
                        return true;
                }
            }
        };
        ExecutorService executorService = new ThreadPoolExecutor(5, 5, 10, TimeUnit.SECONDS,
                                                                 new ArrayBlockingQueue<>(1),
                                                                 new CustomizeThreadFactory("phaser"));
        Random random = new Random();
        for (int i = 0; i < 5; i++) {
            executorService.execute(() -> {
                threadSleep(3000);
                System.out.println("选手[" + Thread.currentThread().getName() + "]，准备完毕");
                phaser.arriveAndAwaitAdvance();


                int num = random.nextInt(2);
                if (num >= 1) {
                    threadSleep(1000);
                    System.out.println("选手[" + Thread.currentThread().getName() + "]，第一关闯关成功");
                    phaser.arriveAndAwaitAdvance();
                } else {
                    System.out.println("选手[" + Thread.currentThread().getName() + "]，第一关闯关失败");
                    phaser.arriveAndDeregister();
                    return;
                }

                num = random.nextInt(2);
                if (num >= 1) {
                    threadSleep(2000);
                    System.out.println("选手[" + Thread.currentThread().getName() + "]，最终关卡闯关成功");
                    phaser.arriveAndAwaitAdvance();
                } else {
                    System.out.println("选手[" + Thread.currentThread().getName() + "]，最终关卡闯关失败");
                    phaser.arriveAndDeregister();
                }

            });
        }

        threadSleep(10000);
        executorService.shutdown();
    }

    static void threadSleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
